<template>
  <div
    v-loading.body.fullscreen.lock="loading"
    :element-loading-text="loadingText"
    ref="containerRef"
    class="container"
  ></div>
  <VideoDialog ref="videoDialogRef" :active="active" />
  <DescDialog ref="descDialogRef" :activeIcon="active">
    <template v-if="active.id == '1'">
      <div class="desc">
        <img class="img" src="/道路图片/服务区.jpg" alt="" />
        <div class="text">
          二郎山隧道服务区（雅康高速天全服务区）是全国首个以大熊猫文化和G318川藏线为主题的双IP超级服务区，被誉为"318入藏第一站"。这座占地107亩的综合性服务区由四川交投集团投资2.8亿元打造，创新性地将大熊猫国家公园元素与川藏公路文化完美融合：主体建筑采用"熊猫进藏"造型，内部设有318公路文化博物馆和大熊猫生态展馆，展出百余件川藏线历史文物和大熊猫保护成果。服务区配备56个充电桩（含8个超充）、24小时热水淋浴房、自助洗衣房、高原特需品超市等特色设施，特别设置"进藏车辆专检区"和"高反应急医疗点"。餐饮区提供藏式牦牛肉火锅、川味小吃等50余种地方美食，并首创"自驾补给包"服务（含便携氧气罐、防滑链等）。2022年升级后新增房车营地、观景平台和文创集市，年接待游客超300万人次，已成为集文化体验、深度补给、旅游休闲于一体的"川藏线会客厅"，其"交通+旅游+文化"模式被交通运输部列为全国示范案例。
        </div>
      </div>
    </template>
    <template v-if="active.id == '2'">
      <div class="desc">
        <img class="img" src="/道路图片/办公室.jpg" alt="" />
        <div class="text">
          二郎山隧道治安交通管理办公室是保障318国道川藏线咽喉要道安全畅通的核心机构，成立于2001年与老隧道同步启用，专门负责二郎山隧道群及周边25公里危险路段的交通治安管理。该办公室创新构建"五位一体"管理体系：通过全线布设的48处高清摄像头与北斗定位系统，对隧道、桥梁及12处地质灾害点进行24小时智能监测；配备专业排障队（含除雪车、清障车等18台特种设备）和应急抢险分队，针对高寒山区特有的冰雪封路（年均45天）、泥石流（雨季频发）等险情，制定"分级响应"预案，最快10分钟抵达事故现场；联合气象部门建立精准预警机制，在隧道两端设置动态限速屏与温控除冰系统。近五年累计处置突发事件327起，救援受困车辆580台次，使事故率下降72%，保障了日均5000辆次的川藏物流与旅游交通。办公室还承担进藏物资运输的优先放行、危化品车辆监管等职能，其首创的"隧道群联动管控"模式已成为全国高海拔公路管理的范本。
        </div>
      </div>
    </template>
    <template v-if="active.id == '3'">
      <div class="desc">
        <div class="text">名称:茶店民主村4组滑坡</div>
        <div class="text">地址:茶店民主村4组</div>
        <div class="text">经纬度:104.3625N,30.53333333E</div>
      </div>
    </template>
    <template v-if="active.id == '4'">
      <div class="desc">
        <div class="text">名称:茶店民主村4组滑坡</div>
        <div class="text">地址:茶店民主村4组</div>
        <div class="text">经纬度:104.3625N,30.53333333E</div>
      </div>
    </template>
    <template v-if="active.id == '5'">
      <div class="desc">
        <div class="text">名称:茶店民主村4组滑坡</div>
        <div class="text">地址:茶店民主村4组</div>
        <div class="text">经纬度:104.3625N,30.53333333E</div>
      </div>
    </template>
  </DescDialog>
</template>
<script setup>
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/addons/renderers/CSS2DRenderer.js";
import {
  CSS3DRenderer,
  CSS3DObject,
} from "three/addons/renderers/CSS3DRenderer.js";
import 出现紧急情况1 from "@/assets/imgs/map/出现紧急情况 (1).png";
import VideoDialog from "./common/videoControlDialog/index.vue";
import DescDialog from "./common/descDialog/index.vue";

import gsap from "gsap";
import { GUI } from "dat.gui";
import 摄像头 from "@/assets/imgs/map/摄像头.png";

import 崩塌 from "/灾害点/崩塌.png";
import 滑坡 from "/灾害点/滑坡.png";
import 泥石流 from "/灾害点/泥石流.png";

import 大巴车 from "@/assets/imgs/map/大巴车.png";
import 货车 from "@/assets/imgs/map/货车.png";
import 轿车 from "@/assets/imgs/map/汽车.png";

import 服务区 from "@/assets/imgs/model2/服务区.png";
import 二郎山办公室 from "@/assets/imgs/model2/二郎山办公室.png";
import {
  generateFluctuatingAltitude,
  generateRandomLicensePlate,
} from "@/utils/index.js";
let renderer,
  scene,
  camera,
  controls,
  gui,
  loader,
  css2Renderer,
  css3Renderer,
  globalTime,
  masterModel,
  draco,
  clock,
  animationFrameId,
  directionalLight,
  ambientLight;
const containerRef = useTemplateRef("containerRef");
const videoDialogRef = useTemplateRef("videoDialogRef");
const descDialogRef = useTemplateRef("descDialogRef");
const loading = ref(false);
const loadingText = ref("加载中...");
const isDark = useDark();
const iconDatas = [
  {
    name: "监控1",
    img: 摄像头,
    label: "频道1",
    id: 1,
    src: "/然乌镇视频/6.mp4",
  },
  {
    name: "监控2",
    img: 摄像头,
    label: "频道2",
    id: 2,
    src: "/然乌镇视频/7.mp4",
  },
  {
    name: "监控3",
    label: "频道3",
    img: 摄像头,
    id: 3,
    src: "/然乌镇视频/8.mp4",
  },
];
const waterIconDatas = [
  {
    id: "freeze",
    name: "路面结冰",
    options: {
      //   offset: [-40, -27, 0],
      rotation: [0, 93, 0],
    },
  },
  {
    id: "water",
    name: "路面积水",
    options: {
      //   offset: [-42, -28, -80],
      rotation: [0, 93, 0],
    },
  },
];
const introduceIconDatas = [
  {
    id: 1,
    name: "二郎山隧道服务区",
    img: 服务区,
    desc: "",
  },
  {
    id: 2,
    name: "二郎山隧道治安交通管理办公室",
    img: 二郎山办公室,
    desc: "名称:茶店民主村4组滑坡。地址:茶店民主村4组",
  },
];
const disasterPoints = [
  {
    id: 3,
    name: "崩塌",
    img: 崩塌,
    position: { x: -20, y: 0, z: -20 },
    des: "",
  },
  {
    id: 4,
    name: "滑坡",
    position: { x: 20, y: -2, z: -20 },
    img: 滑坡,
    des: "",
  },
  {
    id: 5,
    name: "泥石流",
    img: 泥石流,
    position: { x: 40, y: -2, z: -20 },
    des: "",
  },
];
const cardDatas = [
  {
    name: "大巴01",
    url: "/二郎山车辆动画/大巴01.gltf",
    img: 大巴车,
    data: {
      number: generateRandomLicensePlate(),
      type: "大巴车",
      speed: 55,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
  {
    name: "大巴02",
    url: "/二郎山车辆动画/大巴02.gltf",
    img: 大巴车,
    data: {
      number: generateRandomLicensePlate(),
      type: "大巴车",
      speed: 67,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
  {
    name: "货车01",
    url: "/二郎山车辆动画/货车01.gltf",
    img: 货车,
    data: {
      number: generateRandomLicensePlate(),
      type: "货车",
      speed: 62,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
  {
    name: "货车02",
    url: "/二郎山车辆动画/货车02.gltf",
    img: 货车,
    data: {
      number: generateRandomLicensePlate(),
      type: "货车",
      speed: 60,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
  {
    name: "轿车01",
    url: "/二郎山车辆动画/轿车01.gltf",
    img: 轿车,
    data: {
      number: generateRandomLicensePlate(),
      type: "轿车",
      speed: 58,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
  {
    name: "皮卡01",
    url: "/二郎山车辆动画/皮卡01.gltf",
    img: 轿车,
    data: {
      number: generateRandomLicensePlate(),
      type: "皮卡",
      speed: 62,
      altitude: generateFluctuatingAltitude(2100, 100),
    },
  },
];
const active = ref({});
const hasMoved = ref(false); // 是否移动过摄像头
/** 点击视角 */
const watchAngle = () => {
  window.addEventListener("changeAngle", (e) => {
    console.log("www", e.detail);
    const { angle, back } = e.detail;
    if (timer) clearTimeout(timer);
    hasMoved.value = false;
    moveCamera(angle, masterModel.position);
    clearCarLabel();
    clearCarLoop();
    clearLoadIconLabel();
  });
};

/** 点击紧急情况表格 */
const watchHistoryEvent = () => {
  window.addEventListener("clickWateHanle", (e) => {
    console.log("row", e.detail);
    const { row } = e.detail;

    const doms = document.querySelector("." + row.type);
    console.log("doms", doms);
    if (!doms) {
      active.value = row;
      descDialogRef.value.open();
      return;
    }

    // 获取图片
    doms.querySelector(".img").style.display = "block";
    setTimeout(() => {
      doms.querySelector(".img").style.display = "none";
    }, 10000);

    // const index = Math.floor(Math.random() * doms.length)
    // const dom = doms[index];// 随机获取一个dom
    // const item = waterData[index];// 随机获取一个item
    // console.log("item", dom, item);
    // dom.addEventListener('click', (e) => {
    //     e.stopPropagation();
    //     const model = scene.children.find(v => v.name === item.name)
    //     clickWater(item, model);
    // })

    // dom.click()
  });
};

const loadDisasterPoints = () => {
  disasterPoints.forEach((item) => {
    if (!masterModel) return;
    // 创建dom 并设置位置 添加到场景中
    const dom = document.createElement("div");
    dom.className = "disasterPoints";
    dom.innerHTML = `
       <div class="text">${item.name}</div>
       <img class="img" src="${item.img}" alt="">
     `;
    const tag = new CSS2DObject(dom);
    tag.position.set(item.position.x, item.position.y, item.position.z);
    labelElements.push({ dom: dom, object3D: tag });
    // scene.add(tag);
    masterModel.add(tag); // 将标签添加到模型上

    let isShow = false;
    const img = dom.querySelector(".img");
    const text = dom.querySelector(".text");
    img.addEventListener("click", (e) => {
      e.stopPropagation();
      text.style.opacity = isShow ? "0" : "1";
      active.value = item;
      descDialogRef.value.open(text);
      clearCarLabel();
      clearCarLoop();
      clearLoadIconLabel();
      // const modelWorldPos = new THREE.Vector3();
      // obj.getWorldPosition(modelWorldPos);
      // const cameraOffset = new THREE.Vector3(
      //   Math.sin(Date.now() * 0.002) * 5, // X轴动态偏移量
      //   20, // Y轴固定高度
      //   40 // Z轴基础距离
      // );
      // const cameraTargetPos = modelWorldPos.clone().add(cameraOffset);
      // moveCamera(cameraTargetPos, modelWorldPos);
    });
  });
};

const loadIcon = () => {
  if (!masterModel) return;
  iconDatas.forEach((item) => {
    const model = masterModel.children.find(
      (child) => child.name === item.name
    );
    if (!model) return;
    const dom = document.createElement("div");
    dom.className = "road";
    dom.style.pointerEvents = "auto"; // 确保点击事件能触发
    dom.innerHTML = `
     <div class="text textDom">点击查看</div>
    <img class="img" src="${item.img}" alt="">
    `;
    let isShow = false;
    const img = dom.querySelector(".img");
    const text = dom.querySelector(".text");
    img.addEventListener("click", (e) => {
      e.stopPropagation();
      clearLoadIconLabel();
      clearCarLabel();
      clearCarLoop();
      text.style.opacity = isShow ? 0 : 1;
      window.dispatchEvent(
        new CustomEvent("footerClick", { detail: { type: "other" } })
      );
      const modelWorldPos = new THREE.Vector3();
      model.getWorldPosition(modelWorldPos);
      const cameraOffset = new THREE.Vector3(10, 0, 0);
      const cameraTargetPos = modelWorldPos.clone().add(cameraOffset);
      if (active.value.name !== item.name) {
        active.value = item;
        hasMoved.value = false;
        moveCamera(cameraTargetPos, modelWorldPos);
        hasMoved.value = true;
      } else {
        if (hasMoved.value) {
          videoDialogRef.value.open(text);
          hasMoved.value = false; // 重置状态
        } else {
          moveCamera(cameraTargetPos, modelWorldPos);
          hasMoved.value = true;
        }
      }
    });
    const tag = new CSS2DObject(dom);
    labelElements.push({ dom: dom, object3D: tag });
    model.add(tag);
  });
};
const clearLoadIconLabel = () => {
  const textDoms = document.querySelectorAll(".textDom");
  textDoms?.forEach((item) => {
    item.style.opacity = 0;
  });
};

const loadWaterIcon = () => {
  waterIconDatas.forEach((item) => {
    const model = masterModel.children.find(
      (child) => child.name === item.name
    );
    if (!model) return;
    // 复制模型坐标
    const modelWorldPos = new THREE.Vector3();
    model.getWorldPosition(modelWorldPos);

    loader.load(`/${item.name}.gltf`, (gltf) => {
      const waterModel = gltf.scene;
      waterModel.name = item.name;
      // waterModel.position.copy(modelWorldPos); // 复制模型位置
      // waterModel.scale.set(0.0001, 0.0001, 0.0001); // 调整模型大小
      const { rotation } = item.options;
      waterModel.rotation.set(rotation[0], rotation[1], rotation[2]); // 调整模型旋转
      waterModel.position.set(
        modelWorldPos.x,
        modelWorldPos.y,
        modelWorldPos.z
      );
      scene.add(waterModel);
    });

    const dom = document.createElement("div");
    dom.className = item.id;
    dom.innerHTML = `
                    <img class="img" src="${出现紧急情况1}" alt="">
                    <span class="text">${item.name}</span>
                `;
    const tag = new CSS2DObject(dom);
    labelElements.push({ dom: dom, object3D: tag });
    model.add(tag);
  });
};

const introduceIcon = () => {
  if (!masterModel) return;
  introduceIconDatas.forEach((item) => {
    const model = masterModel.children.find(
      (child) => child.name === item.name
    );
    console.log("asdas", model);

    if (!model) return;
    const dom = document.createElement("div");
    dom.className = "introduce";
    dom.innerHTML = `
                <span class="text">${item.name}</span>
                <img class="img" src="${item.img}" alt="">
            `;

    let isShow = false;
    const img = dom.querySelector(".img");
    const text = dom.querySelector(".text");
    img.addEventListener("click", (e) => {
      e.stopPropagation();
      text.style.opacity = isShow ? "0" : "1";
      active.value = item;
      descDialogRef.value.open(text);
      clearCarLabel();
      clearCarLoop();
      clearLoadIconLabel();
      // const modelWorldPos = new THREE.Vector3();
      // obj.getWorldPosition(modelWorldPos);
      // const cameraOffset = new THREE.Vector3(
      //   Math.sin(Date.now() * 0.002) * 5, // X轴动态偏移量
      //   20, // Y轴固定高度
      //   40 // Z轴基础距离
      // );
      // const cameraTargetPos = modelWorldPos.clone().add(cameraOffset);
      // moveCamera(cameraTargetPos, modelWorldPos);
    });

    const tag = new CSS2DObject(dom);
    labelElements.push({ dom: dom, object3D: tag });
    model.add(tag);
  });
};

const carMap = new Map();
const mixers = []; // 全局存储所有动画混合器
let followTarget = null; // 跟踪的目标
const cameraOffset = new THREE.Vector3(10, 5, 0);
const lerpAlpha = 0.06; // 阻尼系数，范围 0–1
const loadCar = () => {
  cardDatas.forEach((item) => {
    loader.load(item.url, (gltf) => {
      const model = gltf.scene;
      // gltf.scene.add(new THREE.AxesHelper(50));
      console.log("gltf", gltf);
      // model.position.set(0, 200, 0);
      // createHelper(model.position);
      // console.log("asdasd", model.position);

      // model.name = item.name;
      scene.add(model);
      // 创建CSS2D标签
      const dom = document.createElement("div");
      dom.className = "card";
      dom.innerHTML = `
                <img class="img" src="${item.img}" alt="">
            `;
      const label = new CSS2DObject(dom);
      label.position.set(0, 10, 0);
      label.name = "label";
      label.visible = true;
      model.children[0].add(label);
      labelElements.push({ dom: dom, object3D: label });
      const dom2 = document.createElement("div");
      dom2.className = "cardPopup";
      dom2.innerHTML = `
            <div class="header">
      <div class="title">车辆信息</div>
        <img src="/prefix/close.png" class="close" alt="">
           </div>
            <div class="content1">
              <div class="item">
                <span>车牌号：</span>
                <span>${item.data.number}</span>
             </div> 
              <div class="item">
                <span>车辆类型：</span>
                <span>${item.data.type}</span>
             </div>
              <div class="item">
                <span>行驶速度：</span>
                <span class="speed">${item.data.speed}km/h</span> 
             </div>
              <div class="item">
                <span>海拔高度：</span>
                <span>${item.data.altitude}M</span>
             </div>
            </div>
            `;
      const label2 = new CSS2DObject(dom2);
      label2.position.set(0, 2, 0);
      label2.name = "popup";
      label2.visible = false;
      model.children[0].add(label2);
      // 创建动画混合器
      const mixer = new THREE.AnimationMixer(model);
      mixer.speed = 0.1;
      mixers.push(mixer);
      // 播放动画
      const action = mixer.clipAction(gltf.animations[0]);
      action.timeScale = 0.5; // 2倍速播放
      action.play();
      // 添加点击事件
      dom.addEventListener("click", (e) => {
        e.stopPropagation();
        clearCarLabel();
        clearCarLoop();
        clearLoadIconLabel();
        closeCardPopup();
        carMap.set(model, {
          initialSpeed: Number(item.data.speed) || 60, // 强制转换为数值
          speedElement: dom2.querySelector(".speed"),
          mixer: mixer,
          currentFactor: 1,
          targetFactor: 3,
          acceleration: 0.003,
          isMaxSpeed: false,
        }); // 存储动画混合器
        clickCar(item, model);
      });
      // 关闭按钮
      dom2.querySelector(".close").addEventListener("click", (e) => {
        e.stopPropagation();
        move();
      });
    });
  });
};
/** 点击汽车标签 */
const clickCar = (item, model) => {
  window.dispatchEvent(
    new CustomEvent("footerClick", { detail: { type: "other" } })
  );
  // 清除之前的标签（popup）
  scene.traverse((child) => {
    if (child.name == "popup") child.visible = false;
  });
  model.children[0].children.find((i) => i.name == "popup").visible = true;
  model.children[0].children.find((i) => i.name == "label").visible = true;
  followTarget = model.children[0];
  const worldPos = new THREE.Vector3();
  const worldQuat = new THREE.Quaternion();
  followTarget.getWorldPosition(worldPos);
  followTarget.getWorldQuaternion(worldQuat);
  // 2. 偏移向量按模型朝向旋转
  const localOffset = cameraOffset.clone().applyQuaternion(worldQuat);
  // 3. 目标相机位置
  const desiredPos = worldPos.clone().add(localOffset);
  // 4. 平滑过渡
  // camera.position.lerp(desiredPos, lerpAlpha);
  controls.target.lerp(worldPos, lerpAlpha);

  moveCamera(masterModel.position, followTarget.position);
  // carloop();
};
/** 隐藏汽车模型标签 */
const clearCarLabel = () => {
  if (timer) clearTimeout(timer);
  scene.traverse((child) => {
    if (child.name == "popup") {
      child.visible = false;
    }
  });
};
const clearCarLoop = () => {
  followTarget = null;
  // requestAnimationFrameId2 && cancelAnimationFrame(requestAnimationFrameId2);
};
/** 加载主体模型 */
const loadModel = () => {
  loading.value = true;
  loader.load(
    "/二郎山.gltf",
    (gltf) => {
      loading.value = false;
      const model = gltf.scene;
      masterModel = model;
      scene.add(masterModel);
      camera.position.set(-100, 0, 100);
      // camera.lookAt(masterModel.position);
      loadCar();
      loadIcon();
      loadWaterIcon();
      introduceIcon();
      loadDisasterPoints();
      console.log("加载完成", model);
    },
    (progress) => {
      const s = progress.loaded / progress.total;
      console.log("加载进度:", s);
      loadingText.value = `加载进度: ${Math.floor(s * 100)}%`;
    },
    (error) => {
      console.error("GLB加载失败:", error);
    }
  );
};
watch(
  () => isDark.value,
  () => {
    if (scene) {
      initLight();
    }
  }
);
const initLight = () => {
  console.log("isDark1111", isDark.value, scene);
  if (ambientLight) scene.remove(ambientLight);
  if (directionalLight) scene.remove(directionalLight);
  if (isDark.value) {
    // 暗黑模式
    // scene.background = new THREE.Color(0x000000);
    // scene.fog = new THREE.Fog(0x000000, 0, 1000000); // Near设为50，避免近处物体完全被雾覆盖
    // if (ambientLight) scene.remove(ambientLight);
    // if (directionalLight) scene.remove(directionalLight);
    // scene.background = new THREE.Color(0x000000); // 黑色
    // ambientLight = new THREE.AmbientLight(0xffffff, 0.0005);
    // scene.add(ambientLight);

    scene.background = new THREE.Color(0x000000);
    scene.fog = new THREE.Fog(0x000000, 50, 10); // Near设为50，避免近处物体完全被雾覆盖
    directionalLight = new THREE.DirectionalLight(0xffffff, 2);
    scene.add(directionalLight);
  } else {
    // 正常模式
    scene.background = new THREE.Color(0x87ceeb); // 天空蓝色
    ambientLight = new THREE.AmbientLight(0xffffff, 1);
    scene.add(ambientLight);
    directionalLight = new THREE.DirectionalLight(0xffffff, 5);
    directionalLight.position.set(5, 10, 5); // 提高光源高度以生成自然投影
    directionalLight.castShadow = true; // 启用阴影投射
    directionalLight.shadow.camera.top = 20;
    directionalLight.shadow.camera.bottom = -20;
    directionalLight.shadow.camera.left = -20;
    directionalLight.shadow.camera.right = 20;
    scene.add(directionalLight);
    scene.fog = null;
  }
  if (renderer) {
    renderer.shadowMap.enabled = true; // 启用阴影贴图
    renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 使用软阴影优化边缘质量
  }
};
const initThree = () => {
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.domElement.style.zIndex = -1;
  containerRef.value.appendChild(renderer.domElement);

  //二郎山
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  controls = new OrbitControls(camera, renderer.domElement);

  // controls.enableDamping = true;
  // controls.dampingFactor = 0.25;
  controls.enablePan = false; // 启用平移
  // 控制器限制
  controls.minDistance = 50; // 最小距离
  controls.maxDistance = 200; // 最大距离

  controls.minPolarAngle = 0; // 0 = 正上方
  controls.maxPolarAngle = Math.PI / 3; // π/2 = 水平视角

  camera.position.set(0, 0, 0);
  controls.target.set(0, 0, 0);
  controls.update();

  initLight();
  // // 添加天空颜色
  // scene.background = new THREE.Color(0x87CEEB); // 天空蓝色

  // // 添加环境光
  // ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  // scene.add(ambientLight);

  // // 添加平行光
  // directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  // directionalLight.position.set(5, 5, 5);
  // scene.add(directionalLight);

  // 创建时钟
  clock = new THREE.Clock();

  // 创建gsap时间线
  globalTime = gsap.timeline({ paused: true });
};

// 创建css2渲染器
const initCSS2Renderer = () => {
  css2Renderer = new CSS2DRenderer();
  css2Renderer.setSize(window.innerWidth, window.innerHeight);
  css2Renderer.domElement.style.position = "absolute";
  css2Renderer.domElement.style.top = "0px";
  css2Renderer.domElement.style.pointerEvents = "none";
  css2Renderer.domElement.classList.add("css2");
  containerRef.value.appendChild(css2Renderer.domElement);
  css2Renderer.domElement.style.zIndex = 0;
};
/** 初始化draco */
const initDraco = () => {
  draco = new DRACOLoader();
  draco.setDecoderPath("/prefix/draco/");
};
/** 初始话loader */
const initLoader = () => {
  loader = new GLTFLoader();
  loader.setDRACOLoader(draco);
};
const labelElements = []; // 存储所有标签DOM
const checkOcclusion = () => {
  const raycaster = new THREE.Raycaster();
  const cameraPosition = camera.position.clone();

  labelElements.forEach(({ dom, object3D }) => {
    // 1. 获取标签的世界坐标（不修改原始值）
    const labelWorldPos = new THREE.Vector3();
    object3D.getWorldPosition(labelWorldPos);

    // 2. 计算射线方向（从相机到标签）
    const rayDirection = labelWorldPos.clone().sub(cameraPosition).normalize();

    // 3. 设置射线（起点稍微靠近相机，避免近裁剪面问题）
    const rayOrigin = cameraPosition
      .clone()
      .add(rayDirection.multiplyScalar(0.1));
    raycaster.set(rayOrigin, rayDirection);

    // 4. 检测遮挡（排除标签自身和透明物体）
    const intersects = raycaster.intersectObjects(scene.children, true);
    const isOccluded = intersects.some((intersect) => {
      return (
        intersect.distance < cameraPosition.distanceTo(labelWorldPos) - 0.1 && // 容差阈值
        !intersect.object.isLabel &&
        !(intersect.object.material && intersect.object.material.transparent)
      );
    });

    // 5. 更新标签可见性
    dom.style.visibility = isOccluded ? "hidden" : "visible";
  });
};

// 添加动画循环
const animate = () => {
  requestAnimationFrame(animate);
  // 更新所有动画混合器
  const delta = clock.getDelta();
  mixers.forEach((mixer) => {
    mixer.getRoot().updateMatrixWorld(true); // 关键：强制更新根节点矩阵
    mixer.update(delta);
  });

  if (followTarget) {
    // 1. 世界空间的位置与旋转
    const worldPos = new THREE.Vector3();
    const worldQuat = new THREE.Quaternion();
    followTarget.getWorldPosition(worldPos);
    followTarget.getWorldQuaternion(worldQuat);
    // 2. 偏移向量按模型朝向旋转
    const localOffset = cameraOffset.clone().applyQuaternion(worldQuat);
    // 3. 目标相机位置
    const desiredPos = worldPos.clone().add(localOffset);
    // 4. 平滑过渡
    // camera.position.lerp(desiredPos, lerpAlpha);
    controls.target.lerp(worldPos, lerpAlpha);
  }
  carMap.forEach((data) => {
    if (!data.speedElement || data.isMaxSpeed) return;
    data.currentFactor += data.acceleration * delta;
    if (data.currentFactor >= data.targetFactor) {
      data.currentFactor = data.targetFactor;
      data.isMaxSpeed = true;
    }
    const currentSpeed = data.initialSpeed * data.currentFactor;
    data.speedElement.textContent = `${currentSpeed.toFixed(1)}km/h`;
    if (data.mixer) {
      data.mixer.speed = data.currentFactor * 0.1;
    }
  });

  // 确保场景矩阵更新
  scene.updateMatrixWorld(true);
  renderer.render(scene, camera);
  controls.update();
  css2Renderer.render(scene, camera);
  checkOcclusion();
};
// 添加窗口resize处理
const onWindowResize = () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
  css2Renderer.setSize(window.innerWidth, window.innerHeight);
  // css3Renderer.setSize(window.innerWidth, window.innerHeight);
};

/** 移动相机 */
const moveCamera = (targetPos, lookAtPos, onComplete) => {
  if (!lookAtPos) return;
  const tl = gsap.timeline({ defaults: { duration: 2, ease: "power2.inOut" } });
  // 位置动画
  tl.to(
    camera.position,
    {
      x: targetPos.x,
      y: targetPos.y,
      z: targetPos.z,
    },
    "start"
  );

  // 目标点动画（同步执行）
  tl.to(
    controls.target,
    {
      x: lookAtPos.x,
      y: lookAtPos.y,
      z: lookAtPos.z,
      onUpdate: () => controls.update(),
    },
    "start"
  );

  // 状态管理
  tl.call(() => {
    controls.enabled = true;
    onComplete?.();
  });
};
/** 创建辅助线 */
const createHelper = (
  position = {
    x: 0,
    y: 0,
    z: 0,
  }
) => {
  const axesHelper = new THREE.AxesHelper(50);
  axesHelper.position.set(position.x, position.y, position.z); // 设置辅助线的位置
  scene.add(axesHelper);
};
onMounted(() => {
  initThree();
  initCSS2Renderer();
  // initCSS3Renderer();
  initDraco();
  initLoader();
  loadModel();
  // addDebugGUI()
  // createHelper();
  animate();
  watchAngle();
  watchHistoryEvent();
  window.addEventListener("resize", onWindowResize);
});

onUnmounted(() => {
  window.removeEventListener("resize", onWindowResize);
  if (renderer) renderer.dispose();
  if (timer) clearTimeout(timer);
});
// 移动相机
const move = () => {
  if (timer) clearTimeout(timer);
  hasMoved.value = false;
  moveCamera({ x: -100, y: 0, z: 100 }, masterModel.position);
  clearCarLabel();
  clearCarLoop();
  clearLoadIconLabel();
};
let timer = null;
/** 5w后自动关闭弹窗 */
const closeCardPopup = () => {
  timer = setTimeout(() => {
    move();
    window.dispatchEvent(
      new CustomEvent("footerClick", { detail: { type: "back" } })
    );
  }, 15000);
};
defineExpose({ move });
</script>
<style scoped lang="scss">
.container {
  width: 100%;
  height: 100%;
}
</style>
